package org.lex.game.sudoku.view.solver;

import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.lex.game.sudoku.model.solver.Decision;
import org.lex.game.sudoku.model.solver.SolverObserver;

public class TextAreaSolverObserver extends JTextArea implements SolverObserver {
	private static final long serialVersionUID = -7599034082911156813L;

	private int decisionLevel = 0;

	public TextAreaSolverObserver() {
		super();
		initialize();
	}

	@Override
	public void beginDecision(Decision d) {
		StringBuilder buf = new StringBuilder();
		this.indent(buf);
		buf.append("Begin decision at (").append(d.row + 1).append(", ").append(d.column + 1).append(")=?")
				.append(d.number);
		buf.append(System.getProperty("line.separator", "\n"));
		this.append(buf.toString());
		this.decisionLevel++;
	}

	@Override
	public void fillCell(int row, int col, int num) {
		StringBuilder buf = new StringBuilder();
		this.indent(buf);
		buf.append("filled cell (").append(row + 1).append(", ").append(col + 1).append(")=").append(num);
		buf.append(System.getProperty("line.separator", "\n"));
		this.append(buf.toString());
	}

	@Override
	public void rollbackDecision(Decision d, int cellCount) {
		this.decisionLevel--;
		StringBuilder buf = new StringBuilder();
		this.indent(buf);
		buf.append("Rollback decision at (").append(d.row + 1).append(", ").append(d.column + 1).append(")=?")
				.append(d.number);
		buf.append(", ").append(cellCount).append(" cells rollbacked");
		buf.append(System.getProperty("line.separator", "\n"));
		this.append(buf.toString());
	}

	@Override
	public void reset() {
		this.setText("");
		this.decisionLevel = 0;
	}

	private StringBuilder indent(StringBuilder buf) {
		for (int i = 0; i < this.decisionLevel; i++) {
			buf.append('\t');
		}
		return buf;
	}

	private void initialize() {
		this.setLineWrap(false);
		this.setEditable(false);
		this.setTabSize(2);
		this.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void insertUpdate(DocumentEvent e) {
				documentChanged();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				documentChanged();
			}

			@Override
			public void changedUpdate(DocumentEvent e) {
				documentChanged();
			}

			private void documentChanged() {
				setCaretPosition(getDocument().getLength());
			}
		});
	}

}
